package com.stone.dao.hibernatebaseimpl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.stone.dao.base.IBaseDao;
import com.stone.utils.Page;

/**
 * DAO的Hibernate实现基类
 * @param <T> POJO的类型
 * @param <ID> ID的类型
 * 
 */
public abstract class BaseDaoHibernateImpl<T, ID extends Serializable> extends
		HibernateDaoSupport implements IBaseDao<T, ID>{
	private Class<T> persistentClass;

	@SuppressWarnings("unchecked")
	public BaseDaoHibernateImpl(){
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public Class<T> getPersistentClass()
	{
		return persistentClass;
	}

	public T findById(ID id){
		return (T) this.getHibernateTemplate().get(getPersistentClass(), id);
	}

	@SuppressWarnings("unchecked")
	public T save(T entity){
		return this.findById((ID)this.getHibernateTemplate().save(entity));
	}

	public void delete(T entity){
		this.getHibernateTemplate().delete(entity);
	}

	public void deleteByProperty(String propertyName, Object value){
		String queryString = "delete from " + getPersistentClass().getName()
				+ " as model where model." + propertyName + "= ?";
		Query query = this.getSession().createQuery(queryString);
		query.setParameter(0, value);
		query.executeUpdate();
	}

	public void saveOrUpdate(T entity){
		this.getHibernateTemplate().saveOrUpdate(entity);
	}

	public void update(T entity){
		this.getHibernateTemplate().update(entity);
	}

	@SuppressWarnings("unchecked")
	public List<T> findAll()
	{
		return this.getHibernateTemplate().find(
				"from " + getPersistentClass().getName());
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll(int page, int pageSize)
	{
		String queryString = "from " + getPersistentClass().getName();
		Query query = this.getSession().createQuery(queryString);
		int firstResult = (page - 1) * pageSize;
		query.setFirstResult(firstResult);
		query.setMaxResults(pageSize);
		return query.list();
	}

	public int countAll(){
		String queryString = "select count(*) from "
				+ getPersistentClass().getName();
		Query query = this.getSession().createQuery(queryString);
		List list = query.list();
		Long result = (Long) list.get(0);
		return result.intValue();
	}

	@SuppressWarnings("unchecked")
	public List<T> findByExample(T entity){
		return this.getHibernateTemplate().findByExample(entity);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByProperty(String propertyName, Object value){
		String queryString = "from " + getPersistentClass().getName()
				+ " as model where model." + propertyName + "= ?";
		return this.getHibernateTemplate().find(queryString, value);
	}

	public List<T> findByPropertys(String[] propertyNames, Object[] values){
		StringBuffer strBuffer = new StringBuffer();
		strBuffer.append("from " + getPersistentClass().getName());
		strBuffer.append(" as model where ");
		for (int i = 0; i < propertyNames.length; i++)
		{
			if (i != 0)
				strBuffer.append(" and");
			strBuffer.append(" model.");
			strBuffer.append(propertyNames[i]);
			strBuffer.append("=");
			strBuffer.append("? ");
		}
		String queryString = strBuffer.toString();
		return this.getHibernateTemplate().find(queryString, values);
	}

	public List<T> findByProperty(String propertyName, Object value, int page,int pageSize){
		return this.findByPropertys(
				new String[]{propertyName},
				new Object[]{value},page,pageSize);
	}
	
	public List<T> findByPropertys(String[] propertyNames, Object[] values,int page, int pageSize){
		StringBuffer strBuffer = new StringBuffer();
		strBuffer.append("from " + getPersistentClass().getName());
		strBuffer.append(" as model where ");
		for (int i = 0; i < propertyNames.length; i++){
			if (i != 0)
				strBuffer.append(" and");
			strBuffer.append(" model.");
			strBuffer.append(propertyNames[i]);
			strBuffer.append("=");
			strBuffer.append("? ");
		}
		String queryString = strBuffer.toString();

		int firstResult = (page - 1) * pageSize;

		Query query = this.getSession().createQuery(queryString);
		query.setFirstResult(firstResult);
		query.setMaxResults(pageSize);
		for (int i = 0; i < values.length; i++){
			query.setParameter(i, values[i]);
		}

		return query.list();
	}
	
	public int countByProperty(String propertyName, Object value){
		String[] propertyNames = new String[]{propertyName};
		Object[] values = new Object[]{value};
		return this.countByPropertys(propertyNames, values);
	}
	
	public int countByPropertys(String[] propertyNames, Object[] values)
	{
		StringBuffer strBuffer = new StringBuffer();
		strBuffer.append("select count(*) from "
				+ getPersistentClass().getName());
		strBuffer.append(" as model where ");
		for (int i = 0; i < propertyNames.length; i++){
			if (i != 0)
				strBuffer.append(" and");
			strBuffer.append(" model.");
			strBuffer.append(propertyNames[i]);
			strBuffer.append("=");
			strBuffer.append("? ");
		}

		String queryString = strBuffer.toString();
		Query query = this.getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++){
			query.setParameter(i, values[i]);
		}

		List list = query.list();
		Long result = (Long) list.get(0);
		return result.intValue();
	}
	
	public Page findByPropertys4Page(String[] propertyNames,Object[] values,int pageno,int pageSize){
		Page page = new Page(countByPropertys(propertyNames,values),pageSize);
		page.setCurrentPage(pageno);
		page.setList(this.findByPropertys(propertyNames, values, pageno, pageSize));
		return page;
	}
	
    public Page findByQueryString4Page(final String queryString,final Object[] values,final int pageno,final int pageSize){
    	try {
			Page page = new Page(this.countByQueryString(queryString, values),pageSize);
			List list = this.getHibernateTemplate().executeFind(new HibernateCallback() {

				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query query = session.createQuery(queryString);
					int len = values.length;
					for(int i = 0;i<len;i++){
						query.setParameter(i, values[i]);
					}
					int firstRecord = (pageno - 1)*pageSize;
					query.setFirstResult(firstRecord);
					query.setMaxResults(pageSize);
					return query.list();
				}
			});
			page.setCurrentPage(pageno);
			page.setList(list);
			return page;
		} catch (Exception e) {
			logger.debug("find by params for page failed",e);
			return null;
		} 
    }
    
    public int countByQueryString(String queryString,Object[] values){
    	try {
    		String countQueryString="select count(*) "+queryString;
    		Long result = (Long)this.getHibernateTemplate().find(countQueryString, values).get(0);
    		return result.intValue();
    	}
    	 catch (Exception e) {
    		logger.debug("get total with query string and params",e);
    		return 0;
    	}
    }
    
    public List<T> findByQueryString(String queryString,Object[] values){
    	Query query = this.getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++)
		{
			query.setParameter(i, values[i]);
		}

		return query.list();
    }
    
    public List<T> findByQueryString(String queryString){
    	Query query = this.getSession().createQuery(queryString);
		return query.list();
    }
}
